#![allow(dead_code)]
trait Park {
    fn park(&self);
}

trait Paint {
    fn paint(&self, color: String) {
        println!("Painting object:{}", color);
    }
}

struct VehicleInfo {
    make: String,
    model: String,
    year: u16,
}

trait Vehicle: Paint {
    fn park(&self);
    fn get_default_color() -> String {
        "red".to_string()
    }
}

struct Car {
    // make: String,
    // model: String,
    // year: u16,
    info: VehicleInfo,
}

impl Park for Car {
    fn park(&self) {
        println!("Parking Car!");
    }
}
impl Paint for Car {}
struct Truck {
    // make: String,
    // model: String,
    // year: u16,
    info: VehicleInfo,
}

impl Truck {
    fn unload(&self) {
        println!("Unloading Truck");
    }
}
impl Paint for Truck {}

struct House {}

impl Paint for House {
    fn paint(&self, color: String) {
        println!("Painting house:{}", color);
    }
}

fn main() {
    println!("Hello, world!");
    let car = Car {
        info: VehicleInfo {
            make: "Ford".to_string(),
            model: "Mustang".to_string(),
            year: 1969,
        },
    };
    let house = House {};
    let object = create_paintable_object();
    let object2 = create_paintable_object1(true);
    let paintable_objects: Vec<&dyn Paint> = vec![&car, &house];

    paint_red(&car);
    paint_red2(&house);
    paint_red(&object);
    paint_red(object2.as_ref());

    paint_vehicle_red(&car);
    paint_vehicle_red(&house);
    paint_vehicle_red(&object);
}

fn paint_red<T: Paint>(object: &T) {
    object.paint("red".to_string());
}

fn paint_red2(object: &impl Paint) {
    object.paint("red2".to_string());
}

fn paint_vehicle_red<T>(object: &T)
where
    T: Paint + Paint,
{
    object.paint("paint_vehicle_red".to_string());
}

fn paint_red3<T>(object: &T)
where
    T: Paint + Park,
{
    object.paint("red3".to_string());
}

fn create_paintable_object() -> impl Paint {
    House {}
}

fn create_vehicle_red<T>(object: &T)
where
    T: Vehicle,
{
    object.paint("create_vehicle_red".to_string());
}

fn create_paintable_object1(vehicle: bool) -> Box<dyn Paint> {
    if vehicle {
        Box::new(Car {
            info: VehicleInfo {
                make: "Ford".to_string(),
                model: "Mustang".to_string(),
                year: 1969,
            },
        })
    } else {
        Box::new(House {})
    }
}
